﻿/*
 * Created by SharpDevelop.
 * User: Guy Fomi
 * Date: 2/6/2011
 * Time: 2:14 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using HtmlAgilityPack;
using System.Net;
using System.Collections.Specialized;
using System.Web.Script.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using FileSystemDatabase;
using TomatoSynchronizer.Entities;

namespace TomatoSynchronizer.Store
{
	/// <summary>
	/// Description of DeviseStore.
	/// </summary>
	public class DeviseStore : IStore<Devise>
	{
		private Site _site;
		public Site site {
			get { return _site; }
			set { _site = value; }
		}
		
		private HtmlWeb _client;
		JavaScriptSerializer serialiser;
		private JsonDatabase db;
		
		public DeviseStore(Site site,HtmlWeb client)
		{
			serialiser = new JavaScriptSerializer();
			db = new JsonDatabase("sites/" + site.Name + "/Devises");
			_site = site;
			_client = client;
		}

		public DeviseStore()
		{
		}
		
		public Devise GetItem(string DeviseId)
		{
			JObject json = null;
			List<Devise> entries = new List<Devise>();
			string url = _site.Url + "/admin/json.php?action=load_currency&currencies_id=" + DeviseId + "&module=currencies";
			
			HtmlDocument doc = _client.Load(url);
			HtmlNode node = doc.DocumentNode.SelectSingleNode("/");
			
			try {
				json = (JObject)JsonConvert.DeserializeObject(node.InnerText);
				foreach (JProperty property in json.Properties()) {
					if (property.Name == "data")
					{
						Devise devise = new Devise(property.Value.ToString());
						if (devise != null)
						{
							devise.Store = this;
							return devise;
						}
					}
				}
			} catch (JsonReaderException) {
				//throw new Exception("Unable to load the currency " + DeviseId + " in site " + _site.Name);
				return null;
			}
			
			return null;
		}
		
		public void PersistItems(List<Devise> items)
		{
			db.Write<List<Devise>>(items,_site.Name);
		}
		
		public Devise InsertDummy()
		{
			var dev = new Devise("Dummy currency","","D",0,"0","XYZ","on");
			dev.id = InsertItem(dev);
			PersistItem(dev);
			return dev;
		}
		
		public void Truncate()
		{
			if(DeleteDummy())
			{
				//we cannot delete the default currency, so we create a dummy default currency
				var dev = InsertDummy();
				
				if(!string.IsNullOrEmpty(dev.id))
				{
					List<Devise> devises = GetItems();
					foreach (Devise devise in devises)
					{
						if(devise.code != "XYZ" && !DeleteItem(devise.id))
						{
							throw new Exception("Could not delete the currency " + devise.title + " in site " + _site.Name);
						}
					}

					//the dummy currency is still in db, we will delete it after inserting the new currencies
					//now we truncate the json db
					db.Truncate();
					
					PersistItem(dev);
				}
				else
				{
//					throw new Exception("Could not insert a dummy currency in site " + _site.Name);
				}
			}
			else
			{
				Devise[] devises = LoadItems();
				foreach (Devise devise in devises)
				{
					if(devise.code != "XYZ" && !DeleteItem(devise.id))
					{
						throw new Exception("Could not delete the currency " + devise.title + " in site " + _site.Name);
					}
				}
				
				db.Truncate();
			}
		}
		
		public bool DeleteDummy()
		{
			var currency = new Devise();
			currency.code = "XYZ";
			
			var currencies = LoadByExample(currency);
			
			foreach(Devise devise in currencies)
			{
				if(!DeleteItem(devise.id))
				{
					return false;
				}
				
				db.Delete<Devise>(devise.id);
			}
			
			return true;
		}
		
		public void PersistItem(Devise item)
		{
			db.Write<Devise>(item,item.id.ToString());
		}
		
		public bool MoveItem(string itemId, string folderId)
		{
			throw new NotImplementedException();
		}
		
		public bool DeleteItem(string itemId)
		{
			var devise = LoadItem(itemId);
			if(devise != null)
			{
				HtmlDocument doc = _client.Load(_site.Url + "/admin/json.php?action=delete_currency&cID=" + devise.id + "&code=" + devise.code + "&module=currencies");

				HtmlNode node = doc.DocumentNode.SelectSingleNode("/");

				IDictionary json = serialiser.Deserialize<IDictionary>(node.InnerText);
				foreach (string key in json.Keys) {
					if (key == "success") {
						var response = bool.Parse(json[key].ToString());
						if(response)
						{
							db.Delete<Devise>(itemId);
						}
						
						return response;
					}
				}

				return false;
			}
			
			throw new Exception("Could not load the currency " + itemId + " from " + _site.Name + " local store");
		}
		
		public Devise[] LoadItems()
		{
			return db.Read<Devise>();						
		}

		public Devise[] LoadByExample(Devise example)
		{
			var _devises = GetItems();
			
			Devise[] devises = db.ReadByExample<Devise>(example);
			
			foreach(Devise devise in devises)
			{
				devise.Store = this;
			}
			return devises;
		}
		
		public Devise LoadItem(string itemId)
		{
			Devise item = db.Read<Devise>(itemId);
			if(item != null)
			{				
				return item;
			}
			
			return null;
		}
		
		public bool Contains(Devise item)
		{
			throw new NotImplementedException();
		}
		
		public List<Devise> GetItems()
		{
			db.Truncate();
			
			List<Devise> Devises = new List<Devise>();
			
			string url = _site.Url + "/admin/json.php?action=list_currencies&module=currencies";
			HtmlDocument doc = _client.Load(url);
			HtmlNode node = doc.DocumentNode.SelectSingleNode("/");
			
			JavaScriptSerializer serialiser = new JavaScriptSerializer();
						
			try
			{
				IDictionary json = serialiser.Deserialize<IDictionary>(node.InnerText);
				foreach(string key in json.Keys)
				{
					if(key == "records")
					{
						object[] recs = (object[])json[key];
						for(int i = 0;i < recs.Length;i++)
						{
							Dictionary<string,object> record = (Dictionary<string,object>)recs[i];
							Devise devise = GetItem(record["currencies_id"].ToString());
							if(devise != null)
							{
								devise.Store = this;
								Devises.Add(devise);
							}
						}
					}
				}
				
				foreach(Devise devise in Devises)
				{
					PersistItem(devise);
				}
				
				PersistItems(Devises);
				
				return Devises;
				
			} catch (ArgumentException)
			{
				foreach(Devise devise in Devises)
				{
					PersistItem(devise);
				}
				
				PersistItems(Devises);
				
				return Devises;				
			}
		}
		
		public bool UpdateItem(Devise item)
		{
//			if(item.is_default == "on" || item.is_default == "1")
//			{
//				var dummyDevise = InsertDummy();
//				DeleteItem(item.id);
//				item.id = InsertItem(item);
//				while(!DeleteDummy())
//				{
//					DeleteItem(item.id);
//					item.id = InsertItem(item);
//				}
//			}
			CookieContainer cookies = new CookieContainer();
			NameValueCollection querystring = new NameValueCollection();

			querystring["code"] = item.code + "aaaa";
			querystring["decimal_places"] = item.decimal_places.ToString();
			querystring["id"] = item.id;
			querystring["symbol_left"] = item.symbol_left;
			querystring["symbol_right"] = item.symbol_right;
			querystring["title"] = item.title;
			querystring["module"] = "currencies";
			querystring["value"] = item.value.ToString();
			querystring["action"] = "save_currency";

			string response = Utility.UploadFileEx("dummy.txt", _site.Url + "/admin/json.php", "devise", "text/html", querystring, cookies);

			IDictionary json = serialiser.Deserialize<IDictionary>(response);
			if (json != null) {
				foreach (string key in json.Keys) {
					if (key == "success") {
						return bool.Parse(json[key].ToString());
					}
				}
			}

			//could not update the devise
			return false;
		}
		
		public string InsertItem(Devise item)
		{
			CookieContainer cookies = new CookieContainer();
			NameValueCollection querystring = new NameValueCollection();

			querystring["code"] = item.code;
			querystring["decimal_places"] = item.decimal_places.ToString();
			querystring["id"] = "";
			querystring["symbol_left"] = item.symbol_left;
			querystring["symbol_right"] = item.symbol_right;
			querystring["title"] = item.title;
			
			if(!string.IsNullOrEmpty(item.is_default))
			{
				querystring["is_default"] = "on";
			}
			
			querystring["module"] = "currencies";
			querystring["value"] = item.value.ToString();
			querystring["action"] = "save_currency";

			string response = Utility.UploadFileEx("dummy.txt", _site.Url + "/admin/json.php", "devise", "text/html", querystring, cookies);

			IDictionary json = serialiser.Deserialize<IDictionary>(response);
			if (json != null) {
				foreach (string key in json.Keys) {
					if (key == "success") {
						if(bool.Parse(json[key].ToString()))
						{
							//get the new currency id
							var devises = GetItems();
							
							foreach(Devise devise in devises)
							{
								//we check if this devise has already been downloaded
								if(devise.code == item.code)
								{
									//must be the new devise
									return devise.id;
								}
							}
						}
						if(response.Contains("ms_error_currency_code_exist"))
						{
							var devises = GetItems();
							
							if(item.code == "XYZ")
							{
								foreach(Devise devise in devises)
								{
									//we check if this devise has already been downloaded
									if(devise.code != item.code)
									{
										devise.is_default = "on";
										UpdateItem(devise);
										return devise.id;
									}
								}
							}
							else
							{
								foreach(Devise devise in devises)
								{
									//we check if this devise has already been downloaded
									if(devise.code == item.code)
									{
										item.id = devise.id;
										UpdateItem(item);
										return item.id;
									}
								}
							}
						}
					}
				}
			}

			//could not save the devise
			throw new Exception("The Devise " + item.title + " has not been synchronized");
//			return string.Empty;
		}
	}
}
